--
-- Author:      name
-- DateTime:    2018-05-28 15:57:48
-- Description: 发送与接收socket消息

local skynet = require "skynet"
local wsnetpack = require "websocketnetpack"
local netpack = require "netpack"
local socket = require "socket"
local log = require "Log"
local config = require "configquery"
local pack_helper = require "pack_helper"
local cjson = require "cjson"
local protobuf 
local helper = {}
local pow = math.pow
local table_clone = table_clone

function helper.load( pbc_env )
	assert(pbc_env)
	debug.getregistry().PROTOBUF_ENV = pbc_env
	protobuf = require "protobuf"
end

--写入socket
local function writePackage( fd, contype, msg )
	local tmpmsg, sz
	if contype == "websocket" then
		tmpmsg, sz = wsnetpack.pack(msg)
	elseif contype == "socket" then
		tmpmsg, sz = netpack.pack(msg)	
	else
		tmpmsg, sz = netpack.pack(msg)
	end
	local ok,err = pcall(socket.write, fd, tmpmsg, sz)
	if not ok then
		log.error('writePackage faild:'..err)
		return false
	end
	return true
end

--取包id
local function readShortPid( text ) --big endian
    return text:byte(5) * 256 + text:byte(6) 
end

--取拓展字节
local function readShortExt( text ) --big endian
    return text:byte(3) * 256 + text:byte(4) 
end

local function readShortLittle( text ) --little endian
    return text:byte(1) + text:byte(2) * 256
end

local function readShortBig( text ) --big endian
    return text:byte(1)*256 + text:byte(2)
end

local function getBytes(...)
    return {...}
end
local function encryptData(content,key)
    key = key or "meili"
    local content_bytes = getBytes(string.byte(content,1,-1))
    local key_bytes = getBytes(string.byte(key,1,-1))
    local pos = 1
    for k,v in pairs(content_bytes) do
        if pos > #key_bytes then
            pos = 1
        end
        content_bytes[k] = ((v + 7)%256) ~ key_bytes[pos]
        pos = pos + 1
    end
    return string.char(table.unpack(content_bytes))
end

--解密
local function decryptData(content,key)
    key = key or "meili"
    local content_bytes = getBytes(string.byte(content,1,-1))
    local key_bytes = getBytes(string.byte(key,1,-1))
    local pos = 1
    for k,v in pairs(content_bytes) do
        if pos > #key_bytes then
            pos = 1
        end
        content_bytes[k] = ((v ~ key_bytes[pos]) - 7 )%256
        pos = pos + 1
    end
    return string.char(table.unpack(content_bytes))
end

--组装pb消息
local function encodePbMsg(pack_name, pack_id, msg_body)
    local msgbody
    if next(msg_body) then
        local status
        status, msgbody = pcall(protobuf.encode, pack_name, msg_body)
        if not status then
            print('encode msg body failed',pack_name,msg_body)
            return
        end
    else
        msgbody = ''
    end
    local sid = math.random(100)
    local ext = sid + 1
    --http://cloudwu.github.io/lua53doc/manual.html#6.4.2
    local msg = string.pack(">H", sid)..string.pack(">H", ext)..string.pack(">H", pack_id)..msgbody
    if msg == nil then
        print('#######msg pack failed'..pack_id)
        return
    end
    
    return msg
end


--组装json包
local function encodeJsonMsg(pack_id, msg_body)
	local msgbody
	if next(msg_body) then
		msgbody = cjson.encode(msg_body)
		if not msgbody then
			log.error('encode json msg body failed')
			return
		end
	else
		msgbody = ''
	end
	--http://cloudwu.github.io/lua53doc/manual.html#6.4.2
	local msg = string.pack(">H", pack_id)..msgbody
	if msg == nil then
		log.error('msg pack failed'..pack_id)
		return
	end
	return msg
end


------------------------------------------
--  pack
------------------------------------------


--发送pb数据
function helper.send_message(fd, conntype, msg_name, args)
	local pack = config.message[msg_name]
	if not pack then
		--assert(false)
		log.error('########send message error no found msg_name:'..msg_name,args)
		return
	end
	local msg_body = {}
	msg_body[msg_name] = args

	if "heart_res" ~= msg_name and "mj_update_state_res" ~= msg_name and "mj_left_card_num_res" ~= msg_name and "mj_result_res" ~= msg_name then
		--log.debug("_______________@@@",fd,msg_body)
	end
	local msg = encodePbMsg(pack[1], pack[2], msg_body)
	if msg then
		-- msg = encryptData(msg)
		return writePackage(fd, conntype, msg)
	else
		log.error('write_package faild :'..msg_name)
	end
end
--解析pb数据
function helper.unpack_message(msgbuf, msgsize)
	-- print("________1______msgbuf__",msgbuf,msgsize)
	local status
	if msgsize < 4 then
		log.error("unpack_message invalid msgsize ".. msgsize)
		return nil, nil		
	end
	msgbuf = skynet.tostring(msgbuf, msgsize)	
	-- print("______________msgbuf__",msgbuf,msgsize)
	-- msgbuf = decryptData(msgbuf)

    local sid = readShortBig(msgbuf)
    local ext = readShortExt(msgbuf) --备用
    local pack_id = readShortPid(msgbuf)
    local pack_name = pack_helper.get_pack(pack_id)
    if not pack_name then
        print('decodeMsg no found pack_id:'..pack_id)
        return
    end
    -- print("____sid,ext,pack_id__________msgbuf__",sid,ext,pack_id,pack_name)
    local  pack_body = msgbuf:sub(5)
    local ok, pack_body = pcall(protobuf.decode, pack_name, pack_body, #pack_body)
    if not ok then
        print('decodeMsg msgbody invalid package', pack_body)
    end
    -- print("___pack_body__",pack_body)
	local msg = {}
	msg = table_clone(pack_body)
	if not msg.heart_req then
		log.debug("########",pack_name,msg)
	end
	return sid,pack_name, msg
end

--解析json数据
function helper.unpack_json_message(msgbuf, msgsize)
	local status
	if msgsize < 2 then
		log.error("unpack_message invalid msgsize", msgsize)
		return nil, nil		
	end
	msgbuf = skynet.tostring(msgbuf, msgsize)
	-- for i=1,#msgbuf do 
	-- 	print(string.format("____%x",msgbuf:byte(i)))
	-- end
	local pack_id = msgbuf:byte(1)*256 + msgbuf:byte(2)  -- big-endian
	local pack_name = pack_helper.get_pack(pack_id)
	if not pack_name then
		log.error("unpack_message invalid package:", pack_id, ' msgsize:',msgsize)
		return nil, nil
	end

	local msgbody = msgbuf:sub(3)
	msgbody = cjson.decode(msgbody)
	if not msgbody then
		log.error("unpack_message body faild:", pack_name, '[',pack_id,':',msgsize,']')
		return nil, nil		
	end
	local msg = {}
	msg[pack_name] = table_clone(msgbody)
	print(pack_name,msg)
	return pack_name, msg
end
--发送josn
function helper.send_json_message(fd, conntype, msg_name, args)
	local pack = pack_helper.get_id(msg_name)
	if not pack then
		print('send_json_message', args)
		-- log.error('send message faild no found msg_name:',msg_name)
		--返回给后台的，可以不用pid
		local msgbody = cjson.encode(args)
		return writePackage(fd, conntype, msgbody)
	end
	--log.debug('send_message',msg_name)
	local msg_body = args
	local msg = encodeJsonMsg(pack, msg_body)
	if msg then
		return writePackage(fd, conntype, msg)
	else
		log.error('writepackage faild :',msg_name)
	end
end

return helper